#!/usr/bin/env ruby

# Copyright (c) 2010-2012 Microsoft Corp.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#	http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

class Array
	def sum
		if size == 0
			return nil
		else
			self.inject(0.0) { |sum, x| sum + x }
		end
	end

	def mean
		if size == 0
			return nil
		else
			self.inject(0.0) { |sum, x| sum + x } / size.to_f
		end
	end

	def moment(n = 2)
		if size <= 1
			return nil
		else
			m = mean
			self.inject(0.0) { |sum, x| sum + (x - m) ** n } / size.to_f
		end
	end

	# unbiased estimator for variance
	def var
		if size <= 1
			return nil
		else
			m = mean
			self.inject(0.0) { |sum, x| sum + (x - m) ** 2 } / (size.to_f - 1)
		end
	end

	def std_dev
		retval = var
		retval == nil ? nil : Math.sqrt(retval)
	end

	def kurtosis
		m4 = moment(4)
		m2 = moment(2)

		if !m4 || !m2 || m2 == 0.0
			return nil
		else
			return m4 / (m2 ** 2)
		end
	end

	def shuffle!
		size.downto(1) { |n| push delete_at(rand(n)) }
		self
	end

	def shuffle
		clone.shuffle!
	end

	def self.correlation_coefficient(v1, v2)
		fail unless v1.length == v2.length

		if v1.length <= 1
			return nil
		end

		m1 = v1.mean
		m2 = v2.mean
		count = v1.length

		sigma1 = Math.sqrt(v1.moment(2))
		sigma2 = Math.sqrt(v2.moment(2))

		sigma12 = 0.0
		count.times { |i| sigma12 += (v1[i] - m1) * (v2[i] - m2) }
		sigma12 /= count

		sigma12 / (sigma1 * sigma2 + 1e-10)
	end
end

